//
// Created by denglibin on 2019/6/18 0018.
//

/**
 *std::move 只是纯粹的将一个左值转化为了一个右值，STL实现基本都已经实现了移动语义，相当于对于 vector<T>::push_back()有两个版本的实现
 * template<typename T>
class Vector
{
    void push_back(T& lval);
    void push_back(T&& rval);
};
 而对应的类型 T 也实现了移动拷贝，如下:
 class T
{
    T(T& other)
    {
        // copy constructor
    }

    T(T&& other)
    {
        // move constructor
    }
};
 代码有性能提升

 完美转发 std::forward()
 当我们将一个右值引用传入函数时，他在实参中有了命名，所以继续往下传或者调用其他函数时，根据C++ 标准的定义，这个参数变成了一个左值。
 那么他永远不会调用接下来函数的右值版本，这可能在一些情况下造成拷贝。为了解决这个问题 C++ 11引入了完美转发，根据右值判断的推倒，
 调用forward 传出的值，若原来是一个右值，那么他转出来就是一个右值，否则为一个左值。
 这样的处理就完美的转发了原有参数的左右值属性，不会造成一些不必要的拷贝。代码如下:

    string A("abc");
    string&& Rval = std::move(A);
    string B(Rval);    // this is a copy , not move.
    cout << A << endl;   // output "abc"
    string C(std::forward<string>(Rval));  // move.
    cout << A << endl;       // output ""

右值引用类型是独立于值的，一个右值引用参数作为函数的形参，在函数内部再转发该参数的时候它已经变成一个左值，并不是他原来的类型。
如果我们需要一种方法能够按照参数原来的类型转发到另一个函数，这种转发类型称为完美转发
 */
#include <iostream>
#include <vector>
#include <string>

void test_forward_1(){
    std::string s("abc");
    std::string &&s1 = std::move(s);
    std::string s2(s1);//拷贝
    std::cout << s <<std::endl; //abc
    std::cout << s1 <<std::endl; //abc
    s1 = "bcd";
    std::cout << s <<std::endl; //bcd
    std::cout << s1 <<std::endl; //bcd
    std::cout << s2 <<std::endl;//abc

    std::string s3(std::forward<std::string>(s1));
    std::cout << s3 << std::endl; //bcd
}
template<typename T>
void print(T& t){
    std::cout << "lvalue:" << t << std::endl;
}
template<typename T>
void print(T&& t){
    std::cout << "rvalue:" << t << std::endl;
}

template<typename T>
void TestForward(T && v){
    print(v);
    print(std::forward<T>(v)); //右值（左值的话不变）传进来后变成了左值，再转成右值
    print(std::move(v));
}

int main55(){
    TestForward(1);

    int x = 2;
    TestForward(x);

    TestForward(std::forward<int>(x));
    int y = 3;
    TestForward(std::move(y));


    return 0;
}